/***************************************************************************
                          Object.cpp  -  description
                             -------------------
    begin                : Tue Aug 27 2002
    copyright            : (C) 2002 by Michiel Visser
    email                : 
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "object.h"
#include "parser.h"
#include <math.h>

namespace Obj
{
//int mcount=0, mcc=0;

/*
TODO: proberen inline member functie te maken en kijken of die kleiner is
*/
static void findIndex(char *str, Object *b, int l, void *space);

void _i_actOnColumns(Object *_this, OList::P resi, EPtr b)
{
	OListPtr table(_this->getEditableList());
	ListObject lobj(table);
	{ ChildrenPainter cp(&lobj);
	  List<OList> rowlist; // make a list of rows
	  if ( table->length() > 0 )
	  { for(OList::Iter i(*table); !!i; i++)
	    { OListPtr olp((*i)->getEditableList());
				olp.detach();
				( new (rowlist) OList() )->take(*olp);
	    }
	    Object *bo=ao();
	    while(true)
	    { OList l;
	      bool stop = false;
	      for(List<OList>::Iter j(rowlist); !!j; j++)
	      { if (!*j) { stop = true; break; }
	        l.takeprependone(*j);
	      }
	      if (stop) 
	        break;
	      {
	        Object::GC lo(NEW_OBJ ListObject(l));
	        b->doStackOperation(bo,lo,TypePtr());
	      	if (bo->vtable!=&vtable_Null) { bo->persist(); resi->prepend(bo); bo=ao(); resi++;}
	      	else bo->~Object();
	      }
	    }
	    objectGC.free(bo);
	  }
	}
}

void _i_toArray(const Object *_this, OList::P array) { ADDSTR(_this->toTyle()); }
OListPtr _i_getConstOrCopiedList(const Object *_this) { OListPtr r; new (r) OList(); return r; }
int _i_toInt(const Object *_this)        { return 0; }
float _i_toFloat(const Object *_this)    { return 0; }
String _i_constToString(const Object *_this) { return ""; }
void _i_shift(Object *_this, Object *o, void *space)    { new (space) NullObject(); }
void _i_insertAt(Object *_this, Object *i, Object *obj) { obj->GCunuse(); }
void _i_removeAt(Object *_this, Object *i,void *space) { new (space) NullObject(); }
bool _i_mod(Object *_this, Object *i)          { return false; }
void _i_negate_bitNot(Object *_this)            {}
int  _i_length(const Object *_this)      { return 0; }
void _i_findIndex(Object *_this, Object *b, void *space) { 	session.m_curTypePtr = 0; new (space) NullObject();}

void _i_apply(const Object *_this, Expr *e, void *space)
{
	e->evaluateToVoid();
	new (space) NullObject();
}

Object *ObjectBase::deReference() const { return (vtable == &vtable_Ref) ? (Object *)(((RefObject *)this)->m_obj) : copy(); }
Object *ObjectBase::value() const       
{	Object *t=(Object *)this;
	while(t->vtable == &vtable_Ref)
		t = ((RefObject *)this)->m_obj;
	return t;
}

/*
  index(o) -> index(i)
  indexCopy(o) -> indexCopy(i)
*/
void _i_indexCopy_i(const Object *_this, int i,void *space)
{	
	OListPtr l(_this->getConstList()); // this getConstList will never result in new list, so children need no GC protection.
  Object::GC *r=l->pnext(i);
 	if (r)
    (*r)->duplicateIn(space);
  else
    new (space) NullObject();
}

Object * _i_index(Object *_this, Object *o)     { int i = o->toInt(); return _this->index(i>=0?i:_this->length()+i); }
Object * _i_index_i(Object *_this, int i)
{	Object *r=ao();
  _this->indexCopy(i,r);
  return r;
}

Object * SelfishList_i_index_i(Object *_this, int i)
{
	OList::P j(&*M_OBJECTS);
	for(;i<0;i++)
		j->prepend(NullObject::obj());
	for (; !!*j; j++)
		if(--i<0) return **j; 
	for(;;)
	{	j->prepend(NullObject::obj());
		if (i==0)
			return **j;
		i--;
		j++;
	}
}


Object * List_i_index_i(Object *_this, int i)
{
	O_LIST->makeEditable();
	_this->vtable = &vtable_SelfishList;
 	return SelfishList_i_index_i(_this,i);
}
void List_i_indexCopy_i(const Object *_this, int i, void *space)
{
  Object::GC *r(M_OBJECTS->pnext(i));
 	if (r) (*r)->duplicateIn(space);
  else new (space) NullObject();
}

Object *ObjectBase::toArrayObject() const
{	OList ol;
	toArray(&ol);
	return (Object *) new (ao()) ListObject(ol);
}

//Object::~Object() {/*_TVAR(p,this,"~Object: ");*/ }

void List_i_GCPaintMyChildren(const Object *_this)
{ FOREACH(OList, O_LIST->getList(), i)
	{	session.GCPaintObject(*i); 
	}
}

void Ref_i_GCPaintMyChildren(const Object *_this)
{ session.GCPaintObject(M_OBJ);
}
void Ref_i_actOnColumns(Object *_this, OList::P resi, EPtr b) { M_OBJ->actOnColumns(resi,b); }
OListPtr Ref_i_getIterList(Object *_this, TypePtr &iterStruct, bool isCopy)
{ return M_OBJ->getIterList(iterStruct,false);
}

void _i_binfunc(Object *_this, Object *o) {}

bool _i_sub(Object *_this, Object *o) { return false; }
bool _i_div(Object *_this, Object *o) { return true; }
int _i_compare(const Object *_this, Object *o) { return _this->typeDiff(o); }

int _i_objCompare(const Object *_this, Object *b) { return _this->typeDiff(b); }

//Object::ClassInitializer NullObject::ci;

//#define max(a,b) ((a)>(b)?(a):(b))
//x##Object::~x##Object() { IF_VERBOSE_OLT(_TVAR(p,this,"~" #x ": ")) }  \

#define DEFOBJCLASS(x) \
void x##_i_duplicateIn(const Object *_this, void *space) { new (space) x##Object(*(x##Object *)_this); } \
void x##_i_destroy(Object *_this) { IF_VERBOSE_OLT(_TV(p,_this); _PRINTF("~" #x ": ");_TRACE;) ((x##Object *)_this)->~x##Object(); IF_VERBOSE_OLT(_TV(p,_this); _PRINTF("Done: ~" #x ": ");_TRACE;) }

DEFOBJCLASS(Null);
DEFOBJCLASS(Ref);
DEFOBJCLASS(String);
DEFOBJCLASS(SelfishString); // selfish copies are selfish themselves. question is whether they are not detached. might not be necessary because 'persist'ing already detaches
DEFOBJCLASS(Integer);
DEFOBJCLASS(Float);
DEFOBJCLASS(List);
DEFOBJCLASS(StringSegment);
DEFOBJCLASS(Expr);
DEFOBJCLASS(Map);
DEFOBJCLASS(RegExp);
DEFOBJCLASS(SelfishList);
DEFOBJCLASS(SelfishMap);
DEFOBJCLASS(ClosuredExpr);
//DEFOBJCLASS(Char);
#undef DEFOBJCLASS

void Char_i_destroy(Object *_this) { IF_VERBOSE_OLT(_TV(p,_this); _PRINTF("~" "Char" ": ");_TRACE;) ((CharObject *)_this)->~CharObject(); }

OList::~OList()
{	
	OListChildrenPainter p(*this);
	erase();
}

MapNode::~MapNode() { if (*(int *)m_keySpace!=0) { SelfPainter sp(m_data); key()->~Object();}  }

MapObject::~MapObject() 
{	
	if (m_rootPtr.isunique())
		erase();
}

void MapObject::erase() 
{	
	ChildrenPainter p((Object *)this); 
	MapNode::P &m_root=*m_rootPtr;
  while (!!m_root)
	{	if (!m_root->m_left) { 
	      m_root.take(m_root->m_right);
		} else if (!m_root->m_right) { 
	      m_root.take(m_root->m_left);
		} else {
			Object *key=m_root->key();
	  	MapNode *l=m_root->m_left;
			m_root->m_left.blindset(l->m_right);
			l->m_right.blindset(m_root);
			m_root.blindset(l);
		}
	}
}

void String_i_mul(Object *_this, Object *o)
{ int i=o->toInt();
	if (i<=0)
	{	M_STRING="";
		return;
	}
  int sl=M_STRING.length();
  String r=String(sl*i);
  char *d=r, *s=M_STRING;
  while(--i>=0)
  { memcpy(d,s,sl);
    d+=sl;
  }
  M_STRING = r;
}

void String_i_findIndex(Object *_this, Object *b, void *space) { Obj::findIndex(M_STRING,b,M_STRING.length(), space); }

static void findIndex(char *str, Object *b, int l, void *space)
{ OList res;
	session.m_curTypePtr = 0;
  OList::P ri(&res);
	String bstr(b->toString());
	if (l>0)
	{	char *as_end=str+l;
    char *bs_end=(char *)bstr+bstr.length();
	  for(char *bs=(char *)bstr; bs!=bs_end;bs++)
		{	char *nbs=bs;
			for(char *as=str; nbs!=bs_end && *as==*nbs; nbs++)
			{	as++;
				if (as==as_end)
				{	ri->prepend(NEW_OBJ IntegerObject(bs-(char *)bstr));
					ri++;
					bs=nbs;
					break;
				}
			}
		}
	}
  new (space) ListObject(res);
}

bool String_i_sub(Object *_this, Object *b) 
{ String bstr(b->toString());
	M_STRING.detach();
	char *begin = 0; // begin of segment to place back
	int shift   = 0; // number of bytes to place back
	if (bstr.length()>0)
	{	char *as_end=(char *)M_STRING+M_STRING.length(), *bs_end=(char *)bstr+bstr.length();
		for(char *as=M_STRING;as!=as_end;as++)
		{	char *nas=as;
			for(char *bs=bstr; nas!=as_end && *bs==*nas; nas++)
			{	bs++;
				if (bs==bs_end)
				{	if (begin)
				  { memcpy(begin-shift,begin, as - begin);
          }
          begin = nas + 1;
          as = nas;
          shift+=bstr.length();
					break;
				}
			}
		}
		if (begin)
		{ memcpy(begin-shift, begin, as_end - begin);
			M_STRING=String((char *)M_STRING,M_STRING.length()-shift); //shrink size
		}
	}
	return M_STRING.length()>0;
}

Object * String_i_index_i(Object *_this, int i)
{	if (i<0 || i>=M_STRING.length()) return NullObject::obj();
  M_STRING.detach();
	_this->vtable=&vtable_SelfishString;
  return NEW_OBJ CharObject(M_STRING,i);
}
Object * SelfishString_i_index_i(Object *_this, int i)
{	if (i<0 || i>=M_STRING.length()) return NullObject::obj();
  return NEW_OBJ CharObject(M_STRING,i);
}

void String_i_indexCopy_i(const Object *_this, int i,void *space)
{	if (i<0 || i>=M_STRING.length()) new (space) NullObject();
  else new (space) StringObject((char *)M_STRING+i,1);
}

String String_i_constToString(const Object *_this) { return M_STRING; }
int String_i_toInt(const Object *_this) 
{ int result, base;
	TyleParser::parseInt((unsigned char *)M_STRING, base, result);
	return result;
}
float String_i_toFloat(const Object *_this) { float f; sscanf((char *)M_STRING, " %f", &f); return f; }
void String_i_prepend(Object *_this, Object *o)
{ String s(o->toString()); 
	M_STRING = M_STRING.length()==0 ? s :  s + M_STRING;
}
int String_i_length(const Object *_this) { return M_STRING.length(); }
void String_i_add(Object *_this, Object *o) 
{ String s(o->toString()); 
	M_STRING = M_STRING + s;
}
#define MINSEGMENTSIZE 8
void String_i_shiftLeft(Object *_this, Object *o,void *space)
{ int l, i=_this->toShiftNumber(o,l=String_i_length(_this));
	l-=i;
  if (i<MINSEGMENTSIZE)
    new (space) StringObject(M_STRING.subset(0,i));
   else
    new (space) StringSegmentObject(M_STRING,(char *)M_STRING,i);
  if (l<MINSEGMENTSIZE)
    M_STRING = M_STRING.subset(i,l);
  else
  { String s(M_STRING);
    ((StringObject *)_this)->~StringObject();
    new (_this) StringSegmentObject(s,(char *)s+i,l);
  }
} 
void SelfishString_i_shiftLeft(Object *_this, Object *o,void *space)
{ int l, i=_this->toShiftNumber(o,l=String_i_length(_this));
	l-=i;
  new (space) StringObject(M_STRING.subset(0,i));
  M_STRING = M_STRING.subset(i,l);
}

void String_i_shiftRight(Object *_this, Object *o,void *space)
{ int l, i=_this->toShiftNumber(o,l=String_i_length(_this));
	l-=i; 
  if (i<MINSEGMENTSIZE)
    new (space) StringObject(M_STRING.subset(l,i)); 
  else
    new (space) StringSegmentObject(M_STRING,(char *)M_STRING+l,i);
  if (l<MINSEGMENTSIZE)
    M_STRING = M_STRING.subset(0,l);
  else
  { String s(M_STRING);
    ((StringObject *)_this)->~StringObject();
    new (_this) StringSegmentObject(s,(char *)s,l);
  }
}

void SelfishString_i_shiftRight(Object *_this, Object *o,void *space)
{ int l, i=_this->toShiftNumber(o,l=String_i_length(_this));
	l-=i; 
  new (space) StringObject(M_STRING.subset(l,i));
  M_STRING = M_STRING.subset(0,l);
}

void String_i_negate(Object *_this)
{ int l=M_STRING.length(),i=l/2; l--;
	M_STRING.detach();
	while(--i>=0)
	{	char t=M_STRING[i];
  	M_STRING[i]=M_STRING[l-i];
  	M_STRING[l-i]=t;
	}
}

#ifndef NO_TEMP_OBJECTS

void Char_i_duplicateIn(const Object *_this, void *space) { new (space) StringObject(M_CHAR->m_ptr,1); }
void Char_i_convertToString(Object *_this) { new ((void *)_this) StringObject(M_CHAR->m_ptr,1); }
Object *   Char_i_index_i(Object *_this, int i) { return (i!=0) ? NullObject::obj(): _this; }
void   Char_i_indexCopy_i(const Object *_this, int i,void *space) { if (i!=0) new (space) NullObject(); else Char_i_duplicateIn(_this,space); }
String Char_i_constToString(const Object *_this) { return String(M_CHAR->m_ptr,1); }
int    Char_i_toInt(const Object *_this) { char c=*M_CHAR->m_ptr; return c>'0'&&c<='9'?c-'0':0; }
float  Char_i_toFloat(const Object *_this) { return Char_i_toInt(_this); }
void   Char_i_prepend(Object *_this, Object *o)  { Char_i_convertToString(_this); String_i_prepend(_this,o); }
void   Char_i_add(Object *_this, Object *o) { Char_i_convertToString(_this); String_i_add(_this,o); }
void   Char_i_shiftLeft(Object *_this, Object *i,void *space) { Char_i_convertToString(_this); String_i_shiftLeft(_this,i,space); }
void   Char_i_shiftRight(Object *_this, Object *i,void *space) { Char_i_convertToString(_this); String_i_shiftRight(_this,i,space); }
bool   Char_i_sub(Object *_this, Object *b) { Char_i_convertToString(_this); return String_i_sub(_this,b); }
void   Char_i_mul(Object *_this, Object *b) { Char_i_convertToString(_this); String_i_mul(_this,b); }
int    Char_i_length(const Object *_this) { return 1; }
void Char_i_findIndex(Object *_this, Object *b, void *space)
{ Obj::findIndex(M_CHAR->m_ptr,b,1,space);
}
OListPtr Char_i_getConstOrCopiedList(const Object *_this) { return StringObject(Char_i_constToString(_this)).getConstList(); }

String StringSegment_i_constToString(const Object *_this) { return String(O_SEG->str(),M_SEG->m_len); }
int    StringSegment_i_toInt(const Object *_this)  { int i=0; sscanf(O_SEG->str(), " %d", &i); return i; }
float  StringSegment_i_toFloat(const Object *_this) { float f; sscanf(O_SEG->str(), " %f", &f); return f; }

void StringSegment_i_add(Object *_this, Object *o) 
{ String s(o->toString());
  String res(M_SEG->m_len+s.length()); 
  memcpy((char *)res,O_SEG->str(), M_SEG->m_len);
  memcpy((char *)res+M_SEG->m_len,(char *)s, s.length());
  O_SEG->convertToString(res);
}

void StringSegment_i_prepend(Object *_this, Object *o) 
{ String s(o->toString());
  String res(M_SEG->m_len+s.length()); 
  memcpy((char *)res+s.length(),O_SEG->str(), M_SEG->m_len);
  memcpy((char *)res,(char *)s, s.length());
  O_SEG->convertToString(res);
}
int    StringSegment_i_length(const Object *_this) { return M_SEG->m_len; }
void StringSegment_i_shiftLeft(Object *_this, Object *o,void *space)
{ int i=_this->toShiftNumber(o,StringSegment_i_length(_this));
  new (space) StringSegmentObject(M_SEG->m_string, O_SEG->str(), i );
  M_SEG->m_ptr+=i; 
  M_SEG->m_len-=i; 
}
void   StringSegment_i_shiftRight(Object *_this, Object *o,void *space) 
{ int i=_this->toShiftNumber(o,StringSegment_i_length(_this));
  new (space) StringSegmentObject(M_SEG->m_string, O_SEG->str() + M_SEG->m_len - i, i );
  M_SEG->m_len-=i;
}
void StringSegmentObject::convertToString(String s)
{ this->~StringSegmentObject();
  new (this) StringObject(s);
}
void StringSegmentObject::convertToString()
{ String s(str(),m_seg->m_len);
	this->~StringSegmentObject();
  new (this) StringObject(s);
}

bool   StringSegment_i_sub(Object *_this, Object *b) { O_SEG->convertToString(); return String_i_sub(_this,b); }
void   StringSegment_i_mul(Object *_this, Object *b) { O_SEG->convertToString(); String_i_mul(_this,b); }
void StringSegment_i_findIndex(Object *_this, Object *b, void *space)
{ Obj::findIndex(O_SEG->str(),b,M_SEG->m_len,space);
}

#endif

void ObjectBase::set(Object *o)
{ 
	if (vtable==&vtable_Char)
	{	*(((CharObject *)this)->m_char)->m_ptr=o->toString()[0];
	}
	else
	{
		Object::Holder h;
		memcpy((Object *)h,this,OBJ_SIZE);//delayed deletion to prevent painting
	  o->duplicateIn((void *)this);
	}
}


Object * StringSegment_i_index_i(Object *_this, int i)
{	O_SEG->convertToString();
  return String_i_index_i(_this,i);
}

void StringSegment_i_indexCopy_i(const Object *_this, int i,void *space)
{	if (i<0 || i>=M_SEG->m_len) new (space) NullObject();
  else new (space) StringObject(O_SEG->str()+i,1);
}

OListPtr StringSegment_i_getConstOrCopiedList(const Object *_this)
{ 
	OListPtr res;
	OList::P ri(new (res) OList());
  for(char *as=O_SEG->str(), *as_end=as+M_SEG->m_len;as!=as_end;as++)
  { ri->prepend(NEW_OBJ StringObject(as,1)); //todo, why not charobject??
    ri++;
  }
  return res;
}

OListPtr String_i_getConstOrCopiedList(const Object *_this)
{ 
	OListPtr res;
	OList::P ri(new (res) OList());
  FOREACHCHAR(M_STRING,s)
  { ri->prepend(NEW_OBJ StringObject(s,1));
    ri++;
  }
  return res;
}

int _i_strcmp(Object *_this, const char *ptr, int len)
{ String s(_this->toString());
  int i = memcmp(ptr,(char *)s,min(len,s.length())); 
	return i==0 ? ( len>s.length() ? 1 : ( len==s.length() ? 0 : -1 ) ) : i; 
}
/*
int String _i_strcmp(Object *_this, const char *ptr, int len) 
{ int i = memcmp(ptr,(char *)M_STRING,min(len,M_STRING.length())); 
	return i==0 ? ( len>M_STRING.length() ? 1 : ( len==M_STRING.length() ? 0 : -1 ) ) : i; 
}
*/
int Char_i_strcmp(Object *_this, const char *ptr, int len)
{ if (len==0) return -1;
  if (*ptr<*M_CHAR->m_ptr) return -1;
  if (*ptr>*M_CHAR->m_ptr) return 1;
  return len>1 ? 1 : 0;
}
int StringSegment_i_strcmp(Object *_this, const char *ptr, int len) 
{ int i = memcmp(ptr,O_SEG->str(),min(len,M_SEG->m_len)); 
	return i==0 ? ( len>M_SEG->m_len ? 1 : ( len==M_SEG->m_len ? 0 : -1 ) ) : i; 
}

template<typename T> inline int sign(const T& i) 
{ return i>0 ? 1:(i==0 ? 0 : -1); 
}

int Integer_i_objCompare(const Object *_this, Object *b) { int i=_this->typeDiff(b); return i ? i: M_INT - b->toInt(); }
int Float_i_objCompare(const Object *_this, Object *b) { int i=_this->typeDiff(b); return i ? i: sign(M_FLOAT - b->toFloat() ); }
int Char_i_objCompare(const Object *_this, Object *b) { int i=_this->typeDiff(b); return i ? i: b->strcmp(M_CHAR->m_ptr,1); }
int StringSegment_i_objCompare(const Object *_this, Object *b) { int i=_this->typeDiff(b); return i ? i: b->strcmp(O_SEG->str(),M_SEG->m_len); }
int String_i_objCompare(const Object *_this, Object *b) { int i=_this->typeDiff(b); return i ? i: b->strcmp(M_STRING,M_STRING.length()); }
int RegExp_i_objCompare(const Object *_this, Object *b) { int i=_this->typeDiff(b); return i ? i: _this->toTyle().strcmp(b->toTyle()); }
int Integer_i_compare(const Object *_this, Object *b) { return sign( M_INT - b->toInt() );}
int Float_i_compare(const Object *_this, Object *b) { return sign(M_FLOAT - b->toFloat() ); }
int Char_i_compare(const Object *_this, Object *b) { return b->strcmp(M_CHAR->m_ptr,1); }
int StringSegment_i_compare(const Object *_this, Object *b) { return b->strcmp(O_SEG->str(),M_SEG->m_len); }
int String_i_compare(const Object *_this, Object *b) { return b->strcmp(M_STRING,M_STRING.length()); }

void Integer_i_add   (Object *_this, Object *o) { M_INT += o->toInt(); }
void Integer_i_mul   (Object *_this, Object *o) { M_INT *= o->toInt(); }
void Integer_i_bitAnd(Object *_this, Object *o) { M_INT &= o->toInt(); }
void Integer_i_bitOr (Object *_this, Object *o) { M_INT |= o->toInt(); }
void Integer_i_bitXor(Object *_this, Object *o) { M_INT ^= o->toInt(); }

bool Integer_i_div(Object *_this, Object *o) { int i=o->toInt(); if(i) { M_INT /= i; return true; } return false; }
bool Integer_i_mod(Object *_this, Object *o) { int b=o->toInt(); if (b==0) return true; M_INT %= b; return false;}
bool Float_i_mod(Object *_this, Object *o)
{
	float b=o->toFloat();
	if(b==0.0) return true;
	return fmod(M_FLOAT,b);
	return false;
}

String Integer_i_constToString(const Object *_this) { char s[10]; sprintf(s,"%i",M_INT); return s; }
bool Integer_i_sub(Object *_this, Object *o) { M_INT -= o->toInt(); return M_INT>=0; }
void Integer_i_negate(Object *_this)              { M_INT = -M_INT; }//-x
void Integer_i_shiftLeft(Object *_this, Object *o,void *space)
{ int i=o->toInt();
	int v=((unsigned int) M_INT)>>(32-i); M_INT <<= i; 
	new (space) IntegerObject(v);
}
void Integer_i_shiftRight(Object *_this, Object *o,void *space)
{ int i=o->toInt();
	int v=M_INT&((1<<i)-1);               M_INT >>= i;
	new (space) IntegerObject(v);
}
int Integer_i_toInt(const Object *_this) { return M_INT; }
float Integer_i_toFloat(const Object *_this) { return (float)M_INT; }

void Float_i_add(Object *_this, Object *o) { M_FLOAT += o->toFloat(); }
void Float_i_mul(Object *_this, Object *o) { M_FLOAT *= o->toFloat(); }

bool Float_i_div(Object *_this, Object *o) { float f=o->toFloat(); if(f) { M_FLOAT /= f; return true;} return false; }

int List_i_length(const Object *_this) { return M_OBJECTS->length(); }  

void List_i_shiftLeft(Object *_this, Object *o,void *space)
{ int i=_this->toShiftNumber(o,List_i_length(_this));
  ListObject *a = new (space) ListObject();
  a->m_objects->takeset(_this->getEditableListQuick(),i);
}
void List_i_shiftRight(Object *_this, Object *o,void *space)
{ int l, i=_this->toShiftNumber(o,l=List_i_length(_this));
  ListObject *a = new (space) ListObject();
  a->m_objects->takeset(_this->getEditableListQuick().next(l-i),i);
}

void _i_toStringList(const Object *_this, List<StringSegment>::P &p)
{ new (*p) StringSegment(_this->constToString());
	p++;
}

void StringSegment_i_toStringList(const Object *_this, List<StringSegment>::P &p)
{ new (*p) StringSegment(M_SEG->m_string,O_SEG->str(),M_SEG->m_len);
	p++;
}

void Char_i_toStringList(const Object *_this, List<StringSegment>::P &p)
{ new (*p) StringSegment(M_CHAR->m_string,M_CHAR->m_ptr,1);
	p++;
}

void List_i_toStringList(const Object *_this, List<StringSegment>::P &p)
{	FOREACH(OList, _this->getList(), i)
	{	(*i)->toStringList(p);
	}
}

///// //todo: _this->function call might be optimizable from down here:

String List_i_constToString(const Object *_this)
{ 
	List<StringSegment> l;
	List<StringSegment>::P pl(&l);
  List_i_toStringList(_this,pl);
	int len=0;
	FOREACH(List<StringSegment>, l, i)
	{	len+=i->m_len;
	}
	String res(len);
	char *p=res;
	FOREACH(List<StringSegment>, l, i)
	{	int ilen=i->m_len;
		memcpy(p,i->m_ptr,ilen);
		p+=ilen;
	}
	return res;
}

void List_i_toArray(const Object *_this, OList::P array)
{ ADDSTR("{ ");
  bool start=true;
  FOREACH(OList,_this->getList(),i)
  { if (start) start=false; else ADDSTR(", ");
    ADDA((*i)->toArrayObject());
  }
  ADDSTR(" }");
}

OListPtr Map_i_getConstOrCopiedList(const Object *_this)
{ // Even for getConstList, data must be copied, because the map might not be part of the paint tree. 
  // In that case, the garbage collection of the temporary list will cause problems.
  OListPtr res;
  new (res) OList();
  OList::P pres(&*res);
  FOREACHM(O_MAP->, 
  { OList e;
    e.prepend(p->m_data->copy());
    e.prepend(p->key()->copy());
    pres->prepend(NEW_OBJ ListObject(e));
    pres++;
  } )

  return res;
}

OListPtr Map_i_getEditableList(Object *_this)
{
	O_MAP->makeEditable(); // we assume this map is under GC, so we can safely share data
  OListPtr res;
  new (res) OList();
  OList::P pres(&*res);
  FOREACHM(O_MAP->,
  { OList e;
    e.prepend(p->m_data);
    e.prepend(p->key()->copy());
    pres->prepend(NEW_OBJ ListObject(e));
    pres++;
  } )

  return res;
}

int  Map_i_compare(const Object *_this, Object *b)
{ 
	{
		ListObject l(Map_i_getConstOrCopiedList(_this));
		int r=l.compare(b);
		ASSERT(session.m_keepMyChildren==0)
		session.m_keepMyChildren = _this;
	}
	session.m_keepMyChildren=0;
}

int Map_i_objCompare(const Object *_this, Object *b)
{ int i=_this->typeDiff(b);
  if (i) return i; 
	{ ChildrenPainter cpt(_this);
	  ChildrenPainter cpb(b);
	  {	ListObject ob(b->getConstList());
			ListObject l(Map_i_getConstOrCopiedList(_this));
			i=l.objCompare(&ob);
		}
	}
	return i;
}

int Map_i_toInt(const Object *_this) { return !*M_ROOTPTR ? 0 : 1; }

static String stringData("data");
static String stringKey("key");

void Map_i_actOnColumns(Object *_this, OList::P resi, EPtr b)
{ 
	TypePtr type;
  {
    TypePtr atype=session.getCurType();
    TypePtr ct= !!atype ? atype->m_childType : TypePtr();
    List<StructElem> l;
    new (l.prependalloc()) StructElem(stringData,ct );
    new (l.prependalloc()) StructElem(stringKey, !!atype ? atype->getKey() : TypePtr() );
		(new (type) Type())->set(l,false);
  }

	{ OListPtr ol(Map_i_getEditableList(_this));
		{
			OListChildrenPainter ocp(*ol);
		  Object *bo=ao();
		  FOREACH(OList, *ol, i)
		  { 
		    b->doStackOperation(bo,*i,type);
	      if (bo->vtable != &vtable_Null) { bo->persist(); resi->prepend(bo); bo=ao(); resi++; }
	      else bo->~Object();
		  }
		  objectGC.free(bo);
		}
	}

}

OListPtr Map_i_getIterList(Object *_this, TypePtr &iterStruct, bool isCopy)
{ 

  OListPtr res; // map must be copied to list of keys at the beginning because other (readonly) functions can change the order of elements
  new (res) OList();
  OList::P pres(&*res);
  FOREACHM(O_MAP->, 
  { pres->prepend(p->key()->copy());
    pres++;
  } )
  TypePtr p(session.getCurType());
  if (!!p) iterStruct=p->getKey();
  /*makeEditable();*/
  return res;

}

OListPtr _i_getIterList(Object *_this, TypePtr &type,bool isCopy)
{
	TypePtr t (session.getCurType());
	if (!!t)
		type = t->m_childType;
	return _this->getEditableList();
}

OListPtr StringSegment_i_getIterList(Object *_this, TypePtr &strct,bool isCopy)
{ 
	if (isCopy) return StringSegment_i_getConstOrCopiedList(_this); 
	OListPtr res;
	OList::P ri(new (res) OList());
	M_SEG->m_string.detach();
	String s(M_SEG->m_string);
  for(char *as=O_SEG->str(), *as_end=as+M_SEG->m_len;as!=as_end;as++)
  { ri->prepend(NEW_OBJ CharObject(s,as));
    ri++;
  }
  return res;
}

OListPtr String_i_getIterList(Object *_this, TypePtr &strct,bool isCopy)
{
	if (isCopy) return String_i_getConstOrCopiedList(_this); 
	OListPtr res;
	OList::P ri(new (res) OList());
	M_STRING.detach();
  FOREACHCHAR(M_STRING,c)
  { ri->prepend(NEW_OBJ CharObject(M_STRING,c));
    ri++;
  }
  return res;
}

OListPtr Char_i_getIterList(Object *_this, TypePtr &strct,bool isCopy)
{ 
	Char_i_convertToString(_this);
	return String_i_getIterList(_this,strct,isCopy);
}

void _i_GCPaintMyChildren(const Object *_this) {}

void ClosuredExpr_i_GCPaintMyChildren(const Object *_this)
{
	Vector<VarValue> &vs = M_BINDING -> m_vars;
	int i;
	for(i=vs.length();--i>=0;)
	{	session.GCPaintObject(vs[i].m_value);
	}
}

void Map_i_GCPaintMyChildren(const Object *_this)
{ FOREACHM(O_MAP->, session.m_childrenPaintStack.prepend(p->key()); session.GCPaintObject(p->m_data);)
}

void _i_selectElements(Object *_this, MapObject &selector, MapObject &output)
{
	ChildrenPainter sh(_this); // keep children also during key copying
	{
	  OListPtr l(_this->getConstList());
	  FOREACH(OList, *l, i)
	  { Object::Holder key;
	    (*i)->indexCopy(0,key);
	    if (!!selector.getOptionalData(key))
	    { Object *o=ao();
	      (*i)->indexCopy(1,o); 
	      output.insertAt(key,o);
	    }
	  }
	}
}
void Map_i_selectElements(Object *_this, MapObject &selector, MapObject &output)
{
  FOREACHM(selector.,
  { Object *data=O_MAP->getOptionalData(p->key()); 
    if (data)
    { output.insertAt(p->key(),data->copy());
    }
  })
}
void Ref_i_selectElements(Object *_this, MapObject &selector, MapObject &output)
{ M_OBJ->selectElements(selector,output);
}
void Ref_i_apply(const Object *_this, Expr *e, void *space) { return M_OBJ->apply(e,space);}
void Expr_i_apply(const Object *_this, Expr *e, void *space)
{
	session.pushStack(e->evaluateToPersistCopy(),session.getCurType());
	M_E->evaluateToCopy(space);
	ASSERT(session.m_keepMyChildren==0);
  session.m_keepMyChildren=(Object *)space;
  session.popStack();
}

void Expr_i_evaluateToCopy(const Object *_this, void *space)
{
	M_E->evaluateToCopy(space);
}

void Expr_i_evaluateToVoid(const Object *_this)
{
	M_E->evaluateToVoid();
}

ClosuredExprObject::ClosuredExprObject(ClosureBindingPtr binding): ObjectBase(&vtable_ClosuredExpr), m_binding(binding) { IF_VERBOSE_OLT(_TV(p,this); _PRINTF("ClosuredExprObject(new): ");_TRACE;); }
ClosuredExprObject::ClosuredExprObject(const ClosuredExprObject &copyFrom) : ObjectBase(&vtable_ClosuredExpr), m_binding(copyFrom.m_binding) { IF_VERBOSE_OLT(_TV(p,this); _PRINTF("ClosuredExprObject(copy): ");_TRACE;);}

void ClosuredExpr_i_apply(const Object *_this, Expr *e, void *space)
{
	session.execPush(M_BINDING->m_scope);
	ClosureBinding *ocs=session.m_curClosures;
	session.m_curClosures=M_BINDING;
	session.pushStack(e->evaluateToPersistCopy(),session.getCurType());
	M_BINDING->m_expr->evaluateToCopy(space);
	ASSERT(session.m_keepMyChildren==0);
  session.m_keepMyChildren=(Object *)space;
  session.m_curClosures = ocs;
  session.popStack();
	session.execPop();
}

void _i_applyToVoid(const Object *_this, Expr *e) 
{
	e->evaluateToVoid();
}
void Null_i_applyToVoid(const Object *_this, Expr *e)
{ 
	session.reportRuntimeError("Casting to / Calling of Null Object."); 
}
void Null_i_apply(const Object *_this, Expr *e, void *space)
{
	Null_i_applyToVoid(_this, e);
	new (space) NullObject();
}

void ClosuredExpr_i_applyToVoid(const Object *_this, Expr *e)
{
	session.execPush(M_BINDING->m_scope);
	ClosureBinding *ocs=session.m_curClosures;
	session.m_curClosures=M_BINDING;
	session.pushStack(e->evaluateToPersistCopy(),session.getCurType());
	M_BINDING->m_expr->evaluateToVoid();
  session.m_curClosures = ocs;
  session.popStack();
	session.execPop();
}

void Ref_i_applyToVoid(const Object *_this, Expr *e)
{
	M_OBJ->applyToVoid(e);
}
void Expr_i_applyToVoid(const Object *_this, Expr *e)
{
	session.pushStack(e->evaluateToPersistCopy(),session.getCurType());
	M_E->evaluateToVoid();
  session.popStack();
}
void ClosuredExpr_i_evaluateToCopy(const Object *_this, void *space)
{
	session.execPush(M_BINDING->m_scope);
	ClosureBinding *ocs=session.m_curClosures;
	session.m_curClosures=M_BINDING;
	IFDEBUGDEEP( printf("Eval(Void): "); M_BINDING->m_expr->printTyle(); printf("\n"); ) 
	M_BINDING->m_expr->evaluateToCopy(space);
  session.m_curClosures = ocs;
	session.execPop();
}
void ClosuredExpr_i_evaluateToVoid(const Object *_this)
{
	session.execPush(M_BINDING->m_scope);
	ClosureBinding *ocs=session.m_curClosures;
	session.m_curClosures=M_BINDING;
	IFDEBUGDEEP( printf("Eval(Void): "); M_BINDING->m_expr->printTyle(); printf("\n"); ) 
	M_BINDING->m_expr->evaluateToVoid();
  session.m_curClosures = ocs;
	session.execPop();
}

void Ref_i_evaluateToCopy(const Object *_this, void *space) { return M_OBJ->evaluateToCopy(space);}

void Ref_i_evaluateToVoid(const Object *_this) { return M_OBJ->evaluateToVoid();}
void _i_evaluateToVoid(const Object *_this) {}
 	
void Integer_i_apply(const Object *_this, Expr *e, void *space)
{
	Object::Holder ao;
	e->evaluateToCopy(ao);
  new (space) IntegerObject(ao->toInt());
}
void Float_i_apply(const Object *_this, Expr *e, void *space)
{
	Object::Holder ao;
	e->evaluateToCopy(ao);
  new (space) FloatObject(ao->toFloat());
}
void String_i_apply(const Object *_this, Expr *e, void *space)
{
	Object::Holder ao;
	e->evaluateToCopy(ao);
  new (space) StringObject(ao->constToString());
}
void RegExp_i_apply(const Object *_this, Expr *e, void *space)
{
	Object::Holder ao;
	e->evaluateToCopy(ao);
  String i(ao->constToString());
	new (space) RegExpObject(i, i.strlen(), ((RegExpObject *)_this)->m_expr->m_mask);
	try
	{	((RegExpObject *)space)->parse();
	} catch(const char *err)
	{
		session.reportRuntimeError(err); 
	}
}
void List_i_apply(const Object *_this, Expr *e, void *space)
{
	Object::Holder ao;
	e->evaluateToCopy(ao);
  new (space) ListObject(ao->getCopiedList());
  session.m_keepMyChildren=(Object *)space;
}
void Map_i_apply(const Object *_this, Expr *e, void *space)
{
	Object::Holder ao;
	e->evaluateToCopy(ao);
	new (space) MapObject();
	ao->addToMap(*(MapObject *)space);
  session.m_keepMyChildren=(Object *)space;
}

void Map_i_findIndex(Object *_this, Object *b, void *space)
{
  MapObject *r=new (space) MapObject();
  b->selectElements(*O_MAP, *r);
  //do not reset session.m_curTypePtr
}

OListPtr List_i_getCopiedList(const Object *_this)
{
	OListPtr r(M_OBJECTS);
  r.detach();
  O_LIST->copyElements(*r);
	return r;
}
void Map_i_toArray(const Object *_this, OList::P array)
{ ADDSTR("{: ");
  bool start=true;
  FOREACHM(O_MAP->, 
  { if (start) start=false; else ADDSTR(", ");
		Object *o = p->key()->toArrayObject();
    if (p->m_data->vtable != &vtable_Null)
    { OList ol;
			ol.prepend(p->m_data->toArrayObject());
			ol.prepend(NEW_OBJ StringObject(" => ") );
			ol.prepend(o);
			ADDA( NEW_OBJ ListObject(ol) );
    }
		else
    	ADDA(o);
  } )
  ADDSTR(" }");
}

int Map_i_length(const Object *_this)
{ int l=0;
  FOREACHM(O_MAP->, { l++;} )
  return l;
}

void ObjectBase::addToMap(MapObject &map) const
{
	if (getTypeNum()==TOT_Map)
	{
	  FOREACHM(((MapObject *)this)->, 
	  { map.insertAt(p->key(),p->m_data->copy());
	  } )
	}
	else
	{
		{
			OListPtr ol(getConstList());
			FOREACH(OList,*ol,i)
			{ Object::Holder oh1;
			  Object *o0=ao();
			  (*i)->indexCopy(0,oh1);
			  (*i)->indexCopy(1,o0);
		    map.insertAt(oh1,o0);
			}
			ASSERT(session.m_keepMyChildren==0)
			session.m_keepMyChildren = (Object *)this;
		}
		session.m_keepMyChildren=0;
	}
}

void Map_i_add(Object *_this, Object *o)
{ o->addToMap(*(MapObject *)_this);
}

bool Ref_i_subFromMap(const Object *_this, MapObject &map) { return M_OBJ->subFromMap(map); }

bool _i_subFromMap(const Object *_this, MapObject &map)
{ bool r=false;
  OListPtr optr(_this->getConstList());
	FOREACH(OList,*optr,i)
	{ Object::Holder key;
    (*i)->indexCopy(0,key);
		if (!!map.getOptionalData(key))
    { r=true;
      Object::Holder rest;
      map.removeAt(key,rest);
    }
	}
	return r;
}
bool Map_i_subFromMap(const Object *_this, MapObject &map)
{ 
	if (&map==_this)
	{	bool r=map.toInt()!=0;
		map.erase();
		return r;
	}
	bool r=false;
  FOREACHM(O_MAP->, 
  { Object *key=p->key();
    if (!!map.getOptionalData(key))
    { r=true;
      Object::Holder rest;
      map.removeAt(key,rest);
    }
  } )
  return r;
}

bool Map_i_sub(Object *_this, Object *o)
{ return o->subFromMap(*(MapObject *)_this);
}

void List_i_prepend(Object *_this, Object *o)
{ 
	OListPtr r(o->getCopiedList());
	OList &l=_this->getEditableListQuick();
	r->end().take(l);
	l.take(*r);
}
void List_i_add(Object *_this, Object *o)
{ OListPtr r(o->getCopiedList());
  _this->getEditableListQuick().end().take(*r);
}
int Expr_i_objCompare(const Object *_this, Object *b)
{
  int i=_this->typeDiff(b);
  if (!i)
  {	session.m_annotate=true;
  	i=_this->toString().strcmp(b->toString());
		session.m_annotate=false;
	}
	return i;
}

int List_i_objCompare(const Object *_this, Object *b)
{
  int i=_this->typeDiff(b);
  if (i) return i;
  OListPtr bl(b->getConstList()); // b is always list as well
	OList::Iter ai(_this->getList()), bi( *bl );
  while(true)
  {
    if ( !ai ) return !bi ? 0 : -1;
    if ( !bi ) return 1;
    int i=(*ai)->objCompare(*bi);
    if ( i ) return i;
    ai++;  bi++;
  }
}
int List_i_compare(const Object *_this, Object *b)
{
	int r=0;
	{
	  OListPtr bl(b->getConstList());
	  OList::Iter ai(_this->getList()), bi( *bl );
		while(!!ai && !!bi)
	  {
	    r=(*ai)->compare(*bi);
	    if ( r!=0 ) break;
	    ai++;  bi++;
	  }
		ASSERT(session.m_keepMyChildren==0)
		session.m_keepMyChildren = b;
	}
	session.m_keepMyChildren = 0;
	return r;
}

ExprObject::ExprObject(EPtr to): ObjectBase(&vtable_Expr), m_e(to) { IF_VERBOSE_OLT(_TV(p,this); _PRINTF("ExprObject(...): ");_TRACE;)}
String Expr_i_constToString(const Object *_this) { return M_E->toTyle(); }
String ClosuredExpr_i_constToString(const Object *_this) 
{	
	ClosureBinding *ocs=session.m_curClosures;
	session.m_curClosures=M_BINDING;
	String res(M_BINDING->m_expr->toTyle());
	session.m_curClosures = ocs;
	return res;
}
void Expr_i_toArray(const Object *_this, OList::P array) { M_E->toExprArray(array); }
void ClosuredExpr_i_toArray(const Object *_this, OList::P array)
{	
	ClosureBinding *ocs=session.m_curClosures;
	session.m_curClosures=M_BINDING;
	M_BINDING->m_expr->toExprArray(array);
	session.m_curClosures = ocs;
}
OListPtr Expr_i_getConstOrCopiedList(const Object *_this)
{	OListPtr p;
	new (p) OList();
	_this->toArray(&*p);
	return p;
}

bool _i_containsRef(const Object *_this)
{	return false;
}
bool Ref_i_containsRef(const Object *_this)
{	return true;
}
bool List_i_containsRef(const Object *_this)
{	FOREACH(OList, *M_OBJECTS, i)
	{	if ((*i)->containsRef()) return true;
	}
	return false;
}
bool Map_i_containsRef(const Object *_this)
{	FOREACHM(O_MAP->, if (p->key()->containsRef() || p->m_data->containsRef() ) return true;)
	return false;
}
EPtr _i_makeExpr(const Object *_this)
{
	EPtr e;
	new (e) ConstExpr(_this->copy());
	return e;
}

EPtr Ref_i_makeExpr(const Object *_this)
{
	EPtr e;
	new (e) ReferenceExpr(M_OBJ->makeExpr() );
	return e;
}
EPtr List_i_makeExpr(const Object *_this)
{
	EPtr res;
	if (!List_i_containsRef(_this))
	{ new (res) ConstExpr(_this->copy());
		return res;
	}
	ListExpr *s=new (res) ListExpr();
  ListExpr::P sp(&(s->m_elements));
	FOREACH(OList, *M_OBJECTS, i)
	{	sp->prepend ( ListExpr::Elem((*i)->makeExpr(),true) );
		sp++;
	}
	return res;	
}
EPtr Map_i_makeExpr(const Object *_this)
{	
	EPtr res;
	if (!Map_i_containsRef(_this))
	{ new (res) ConstExpr(_this->copy());
		return res;
	}
  MapExpr *s=new (res) MapExpr();
	List<EPtr>::P sp(&(s->m_elements));
	FOREACHM(O_MAP->,
	{	sp->prepend ( p->key()->makeExpr() );
		sp++;
		if (p->m_data->vtable == &vtable_Null)
			sp->prepend(EPtr());
		else
			sp->prepend(p->m_data->makeExpr());
		sp++;
	})
	return res;	
}

EPtr ClosuredExpr_i_makeExpr(const Object *_this)
{
#if 1
	OList arr;
	OList::P array(&arr);
	ADDSTR("( ");

	int l=M_BINDING->m_vars.length();
	List<Closure>::Iter ci(((ClosureScope &)(*M_BINDING->m_scope)).m_closures);	
	for(int i=0; i<l; i++, ci++)
	{
		TypePtr type(M_BINDING->m_vars[i].m_type);
		if (!type->isEmpty())
		{	List<TypeFunc> funcs; //empty
			ADDA(bracketize(type->toArrayObject(funcs)));
		}
		ADDSTR(".");
		ADDSTR(ci->name);

		Object *o=M_BINDING->m_vars[i].m_value;
		if (o->vtable!=&vtable_Null)
		{	
			ADDSTR(" = ");
			ADDSTR(o->toTyle());
		}
		ADDSTR(";");
	}
	ADDSTR(((ClosuredExprObject *)_this)->toTyle());
	ADDSTR(")");
	Object::Holder ao;
	new (ao) ListObject(arr);
	String s(ao->toString());
	EPtr res;
	TyleParser t((unsigned char *)s, res, 0);
	return res;
#else
	_TRACE;
	EPtr r;
	SequenceExpr *se = new (r) SequenceExpr();
	//EList::P ep(&);
	LocalVarVectorQueue::Ptr queue;
  new (queue) LocalVarVectorQueue();
	se->m_queue = queue;
	se->m_elements.prepend(M_BINDING->m_expr);

	int l=M_BINDING->m_vars.length();
	List<Closure>::Iter ci(((ClosureScope &)(*M_BINDING->m_scope)).m_closures);	
	for(int i=0; i<l; i++, ci++)
	{
		EPtr e=queue->insertVar(ci->name,true);
		TypePtr type(M_BINDING->m_vars[i].m_type);
		if (!!type)
		{	EPtr te;
			List<TypeFunc> funcs; //empty
			(new (te) TypeSelectionExpr(new TypeSelection(type), funcs ))->a=e;
			e=te;
		}

		Object *o=M_BINDING->m_vars[i].m_value;
		if (o->vtable==&vtable_Null)
		{	se->m_elements.prepend(e);
		}
		else
		{	
			EPtr ve,as;
			new (ve) ConstExpr(o->copy());
			new (as) AssignmentExpr(e,ve);
			se->m_elements.prepend(as);
		}
	}
	return r;
#endif
}

void List_i_findIndex(Object *_this, Object *b, void *space) 
{ 
	session.m_curTypePtr = 0;
	{
  	OList res;
		OListPtr br(b->getConstList()); 
		if (!!_this->getList())
		{	OList::P ri(&res);
			int c=0;
	  	for(OList::Iter i(*br);!!i;)
	  	{ OList::Iter ib(i),ia(_this->getList());
	    	int tc=c;
	    	for(;;ia++,ib++,tc++)
				{	if (!ia) 
	  			{	ri->prepend(NEW_OBJ IntegerObject(c));
						ri++; 
						i=ib; c=tc;
						break;
					}
	  			if (!ib || !(**ia==*ib)) { c++; i++; break;}	
				}
			}
	  }
	  new (space) ListObject(res);
		ASSERT(session.m_keepMyChildren==0)
		session.m_keepMyChildren = b;
	}
	session.m_keepMyChildren=0;
}

bool List_i_sub(Object *_this, Object *b)
{ 
	bool found=false;
	{
		OListPtr br(b->getConstList());
		int blen=br->length();
		if (blen)
		{ for(OList::P i(&_this->getEditableListQuick());!!i;)
	    { OList::Iter ia(*i),ib(*br);
		    for(;;ib++,ia++)
	  		{	if (!ib) { i->removeset(blen); found=true; break;}
		  		if (!ia || !(**ia==*ib)) { i++; break;}	
	  		}
	    }
	  }
	}
	return found; 
} //-= y

void List_i_insertAt(Object *_this, Object *oi, Object *obj)
{ int i=oi->toInt();
  if (i<0) i+=M_OBJECTS->length()+1;
	OList &l=(OList &)(_this->getEditableListQuick().next(i)); l.prepend(obj);
}
void List_i_removeAt(Object *_this, Object *io,void *space)
{ int i=io->toInt();
  int l=M_OBJECTS->length();
  if (i<0) { i+=l; if (i<0) { new (space) NullObject(); return; } }
  if (i>=l) { new (space) NullObject(); } 	
  else
  { {	OList o; 
	  	o.takeone(_this->getEditableListQuick().next(i)); 
	  	(*o)->duplicateIn(space);
			ASSERT(session.m_keepMyChildren==0)
			session.m_keepMyChildren = (Object *)space;
		}
		session.m_keepMyChildren = 0;
  } 
}
OListPtr List_i_getConstList(const Object *_this) { return M_OBJECTS; }
void List_i_negate(Object *_this) { _this->getEditableListQuick().inverse(); }//-x

void List_i_bitNot(Object *_this)
{
	OList res;
	OList::P rp(&res);
	OList &l=_this->getEditableListQuick();
	FOREACH(OList, l, i)
	{	OListPtr r((*i)->getCopiedList());
		rp->take(*r);
		rp=&rp->end();
	}
	l.take(res);
}

void Expr_i_bitNot(Object *_this)
{
	session.m_annotate=true;
	OList ol;
	_this->toArray(&ol);
	session.m_annotate=false;
	_this->~Object();
	new (_this) ListObject(ol);
}

void List_i_mul(Object *_this, Object *o)
{	int i=o->toInt();
	OList &l=_this->getEditableListQuick();
	OList res;
	if (i<=0)
	{	l.erase();
		return;
	}
	while(--i>0)
	{	OList cl(*M_OBJECTS);// will make copy of list (not of elements)
		res.takeprependall(cl);
	}
	O_LIST->copyElements(res);
	l.end().take(res);
}
bool String_i_div(Object *_this, Object *o)
{	int i=o->toInt();
	if (i)
	{ int j=M_STRING.length()/i;
		char *s=(char *)M_STRING;
		OList res;
		OList::P rp(&res);
		while(--i>0)
		{ rp->prepend( NEW_OBJ StringSegmentObject(M_STRING,s,j));
			s+=j;
			rp++;
		}
		if (i==0)
		{	rp->prepend( (Object *)new(ao()) StringSegmentObject(M_STRING,s,M_STRING.length()-(s-(char *)M_STRING)));
		}	
		((StringObject *)_this)->~StringObject();
		new (_this) ListObject(res);
		return true;
	}
	return false;
}

bool List_i_div(Object *_this, Object *o)
{	int i=o->toInt();
	OList &l=_this->getEditableListQuick();
	if (i)
	{ int j=l.length()/i;
		OList res;
		OList::P rp(&res);
		while(--i>0)
		{ ListObject *lo;
      rp->prepend( (Object *)lo=new (ao()) ListObject());
      lo->m_objects->takeset(l,j);
			rp++;
		}
		if (i==0)
		{	ListObject *lo;
      rp->prepend( (Object *)lo = new(ao()) ListObject());
      lo->m_objects->take(l);
		}	
		l.take(res);
		return true;
	}
	return false;
}
bool List_i_mod(Object *_this, Object *bo)
{	OList res;
  OList &l=_this->getEditableListQuick();
	int b=bo->toInt();
	if(b==0) return true;
  if (b>0)
  {
  	OList::P rp(&res);
  	OList::P rps[b];
  	for(int i=b;--i>=0;rp++)
  	{ ListObject *lo;
  	  rp->prepend((Object *)lo=new (ao()) ListObject());
      rps[i]=&*lo->m_objects;
  	}
  	for(;;)
  	{	for(int i=b;--i>=0;)
  		{	if (!l) goto finish;
  			rps[i]->takeone(l);
  			rps[i]=&rps[i]->end();
  		}
  	}
  }
finish:
	l.take(res);
	return false;
}

int List_i_toInt(const Object *_this) { return _this->getList().valid(); }

void Integer_i_bitNot(Object *_this)  { M_INT = ~M_INT; }

String Float_i_constToString(const Object *_this)
{ char s[20]; 
	int l=sprintf(s,"%g",M_FLOAT),i=l; 
	while(--i>=0)
	{	if (s[i]=='e'||s[i]=='.') return s;
	}
	s[l]='.';
	s[l+1]='0';
	s[l+2]=0;
	return s; 
}
bool Float_i_sub(Object *_this, Object *o) { M_FLOAT -= o->toFloat(); return M_FLOAT>=0; }
void Float_i_negate(Object *_this)              { M_FLOAT = -M_FLOAT; }//-x
float Float_i_toFloat(const Object *_this) { return M_FLOAT; }
int Float_i_toInt(const Object *_this) { return (int)M_FLOAT; }

String Ref_i_toTyle(const Object *_this) { return String("&")+M_OBJ->toTyle(); }
String RegExp_i_toTyle(const Object *_this) { return M_REGEXP->toTyle(); }
String Integer_i_toTyle(const Object *_this) { return Integer_i_constToString(_this); }
String Float_i_toTyle(const Object *_this) { return Float_i_constToString(_this); }
String Char_i_toTyle(const Object *_this) { return StringObject(Char_i_constToString(_this)).toTyle(); }
String StringSegment_i_toTyle(const Object *_this) { return StringObject(StringSegment_i_constToString(_this)).toTyle(); }
String Null_i_toTyle(const Object *_this) { return "()"; }
String ExprListMap_i_toTyle(const Object *_this) { String s((Object::Own(_this->toArrayObject()))->constToString()); return s; }
String String_i_toTyle(const Object *_this)
{ String s(M_STRING.length()*4+2);
  unsigned char *sp=(unsigned char *)s;
  *(sp++)='\"';
  FOREACHUCHAR(M_STRING,i)
  { switch (*i)
		{
		case '\n':  *(sp++)='\\'; *(sp++)='n'; break;
		case '\r':  *(sp++)='\\'; *(sp++)='r'; break;
		case '\t':  *(sp++)='\\'; *(sp++)='t'; break;
		case '\0':  *(sp++)='\\'; *(sp++)='0'; break;
		case '\"':
		case '\\':  *(sp++)='\\'; *(sp++)= *i; break;
		default:		
    	if (*i<' ' || *i == 255 ) { sprintf((char *)sp,"\\x%0.2x", *i); sp+=4; }
    	else
    		*(sp++)=*i;
			break;
    }
  }
  *(sp++)='\"';
  return s.subset(0,sp-(unsigned char *)s);
}

void Ref_i_toArray(const Object *_this, OList::P array)
{ ADDSTR("& ");
  ADDA(M_OBJ->toArrayObject());
}
OListPtr Ref_i_getConstList(const Object *_this) { return M_OBJ->getConstList(); }
OListPtr Ref_i_getCopiedList(const Object *_this) { return M_OBJ->getCopiedList(); }
int Ref_i_toInt(const Object *_this)          { return M_OBJ->toInt(); }
float Ref_i_toFloat(const Object *_this)      { return M_OBJ->toFloat(); }
String Ref_i_constToString(const Object *_this) { return M_OBJ->constToString(); }
void Ref_i_shiftLeft(Object *_this, Object *o,void *space)      { M_OBJ->shiftLeft(o,space); }
void Ref_i_shiftRight(Object *_this, Object *o,void *space)     { M_OBJ->shiftRight(o,space); }
void Ref_i_insertAt(Object *_this, Object *i, Object *obj)       { M_OBJ->insertAt(i,obj); }
void Ref_i_removeAt(Object *_this, Object *i,void *space)                 { M_OBJ->removeAt(i,space); }
void Ref_i_negate(Object *_this)                        { M_OBJ->negate(); }
bool Ref_i_mod(Object *_this, Object *i)                      { return M_OBJ->mod(i); }
Object * Ref_i_index_i(Object *_this, int i)                        { return M_OBJ->index(i); }
Object * Ref_i_index(Object *_this, Object *i)                    { return M_OBJ->index(i); }
void Ref_i_indexCopy_i(const Object *_this, int i,void *space)              { M_OBJ->indexCopy(i,space); }
void Ref_i_bitNot(Object *_this)                        { M_OBJ->bitNot(); }
int  Ref_i_length(const Object *_this)                  { return M_OBJ->length(); }
void Ref_i_findIndex(Object *_this, Object *b, void *space) { M_OBJ->findIndex(b,space);}
String ObjectBase::toString() const //todo: make function static
{	Object *_this=(Object *)this;
	while(_this->vtable == &vtable_Ref) _this=M_OBJ;
	String s(_this->constToString());
	if (_this->vtable==&vtable_StringSegment)
		O_SEG->convertToString(s);
	return s; 
}

void ObjectBase::indexCopy(Object *key,void *space) const //todo: make function static
{	Object *_this=(Object *)this;
	while(_this->vtable == &vtable_Ref) _this=M_OBJ;
	if (_this->getTypeNum()==TOT_Map)
	{ Object *r=O_MAP->getOptionalData(key);
	  if (!r)
	   new (space) NullObject();
	  else
	    (*M_ROOTPTR)->m_data->duplicateIn(space);
	}
	else
	{ int i = key->toInt(); indexCopy(i>=0?i:length()+i,space); 
	}
}

void SelfishMap_i_persist (Object *_this) // todo: make resursiveness stackfree
{	_this->vtable = &vtable_Map;
	O_MAP->makeEditable();
	FOREACHM(O_MAP->,
  { p->m_data->persist();
  } )
}

void SelfishList_i_persist (Object *_this) // todo: make resursiveness stackfree
{	_this->vtable = &vtable_List;
	O_LIST->makeEditable();
	FOREACH(OList, *O_LIST->m_objects, i) 
		(*i)->persist();
}

void SelfishString_i_persist (Object *_this)
{ _this->vtable = &vtable_String;
	O_STRING->m_string.detach();
}

void Ref_i_add    (Object *_this, Object *o) { M_OBJ->add(o); }
void Ref_i_mul    (Object *_this, Object *o) { M_OBJ->mul(o); }
void Ref_i_prepend(Object *_this, Object *o) { M_OBJ->prepend(o); }
void Ref_i_bitAnd (Object *_this, Object *o) { M_OBJ->bitAnd(o); }
void Ref_i_bitOr  (Object *_this, Object *o) { M_OBJ->bitOr(o); }
void Ref_i_bitXor (Object *_this, Object *o) { M_OBJ->bitXor(o); }

bool Ref_i_sub(Object *_this, Object *b) { return M_OBJ->sub(b); }
bool Ref_i_div(Object *_this, Object *b) { return M_OBJ->div(b); }
int Ref_i_objCompare(const Object *_this, Object *b) { int i=_this->typeDiff(b); return i ? i : ( (int)(Object *)b->deReference() - (int)(Object *)M_OBJ ); }
int Ref_i_compare(const Object *_this, Object *b) { return M_OBJ->compare(b);  }

OListPtr Ref_i_getEditableList(Object *_this) { return M_OBJ->getEditableList();  }
OListPtr _i_getEditableList(Object *_this) { return _this->getConstList();  }

OListPtr List_i_getEditableList(Object *_this)
{ O_LIST->makeEditable();
	return M_OBJECTS;
}

void ListObject::makeEditable()
{	if (!m_objects.isunique())
	{ m_objects.detach();
	  copyElements(*m_objects);
	}
}

//void MapObject::makeEditable() {	m_rootPtr.detach(); /* copies all elements */}

void List_i_bitAnd(Object *_this, Object *b)
{ 
	OListPtr bl(b->getConstList());
	OList::P i=&_this->getEditableListQuick();
	while(!!*i)
	{	if (!bl->contains(***i))
			i->removeone();
		else i++;
	}	
}
void List_i_bitOr(Object *_this, Object *b)
{
	{ 
		OListPtr bl(b->getConstList());
		OList &l=_this->getEditableListQuick();
		FOREACH(OList,*bl,j)
		{	if (!l.contains(**j))
			{	l.prepend((*j)->copy());
			}
		}
		ASSERT(session.m_keepMyChildren==0)
		session.m_keepMyChildren = b;
	}
	session.m_keepMyChildren=0;
}
void List_i_bitXor(Object *_this, Object *b)
{ 
	OListPtr bl(b->getConstList());
	OList &l=_this->getEditableListQuick();
	FOREACH(OList,*bl,j)
	{	OList &p=(OList &)(l.find(**j));
  	if (!p)
		{	l.prepend((*j)->copy());
		} else
		{ p.removeone();
		}
	}
}

#define ROLXOR(x,y) ( ((x<<8)|(x>>24)) ^ (y) )
#define HASHF(v,t) ( ((int)(v)) ^ (TOT_##t*0x1010101) )
int _i_hash(const Object *_this) { return 0; }
int Ref_i_hash(const Object *_this) { return HASHF((Object *)M_OBJ,Ref); }
int Integer_i_hash(const Object *_this) { return HASHF(M_INT,Int); }
int Float_i_hash(const Object *_this) { return HASHF(*(int *)&M_FLOAT,Float); }
int String_i_hash(const Object *_this) 
{   int hash=0, i;
    int split=M_STRING.length() & ~3;
    for(i=M_STRING.length(); --i>= split;)
        hash=(hash<<8) | M_STRING[i];
    for(i=split >> 2 ; --i>=0;)
        hash=ROLXOR(hash, ((int *)(char *)M_STRING)[i] );
    return HASHF(hash,String);
}
int Char_i_hash(const Object *_this) { return HASHF(*M_CHAR->m_ptr,String); }
int List_i_hash(const Object *_this)
{   unsigned int hash=0; 
    FOREACH(OList, *M_OBJECTS, i) hash=ROLXOR(hash, (*i)->hash()); 
    return HASHF(hash,List);
}
int Map_i_hash(const Object *_this)
{   unsigned int hash=0;
    FOREACHM(O_MAP->, { hash=ROLXOR(hash, p->key()->hash()); hash=ROLXOR(hash, p->m_data->hash()); } ) 
    return HASHF(hash,Map);
}
    
int Expr_i_hash(const Object *_this) { return HASHF(StringObject(ExprListMap_i_toTyle(_this)).hash(),Expr); }
int ClosuredExpr_i_hash(const Object *_this) { return HASHF(StringObject(ExprListMap_i_toTyle(_this)).hash(),Expr); }
int RegExp_i_hash(const Object *_this) { return HASHF(StringObject(_this->toTyle()).hash(),RegExp); }
int StringSegment_i_hash(const Object *_this) 
{   int hash=0, i;
    char *s=O_SEG->str();
    int split=M_SEG->m_len & ~3;
    for(i=M_SEG->m_len; --i>= split;)
        hash=(hash<<8) | s[i];
    for(i=split >> 2 ; --i>=0;)
        hash=ROLXOR(hash, ((int *)s)[i]); 
    return HASHF(hash,String);
}

Object *SelfishMap_i_index(Object *_this, Object *key);

Object * Map_i_index(Object *_this, Object *key)
{ 
	O_MAP->makeEditable();
	_this->vtable=&vtable_SelfishMap;
  return SelfishMap_i_index(_this,key);
}

Object * Map_i_index_i(Object *_this, int i)
{ IntegerObject oi(i);
  return Map_i_index(_this,&oi);
}

void Map_i_indexCopy_i(const Object *_this, int i,void *space)
{ IntegerObject io(i);
  return _this->indexCopy(&io,space);
}

void Map_i_insertAt(Object *_this, Object *key, Object *obj)
{
	int c;
	O_MAP->makeEditable();
	MapNode::P &m_root=*M_ROOTPTR;
  if (!m_root) {
    m_root = new MapNode(key,obj);
	}
	else
	{	O_MAP->splay(key);
		if ((c = key->objCompare(m_root->key())) != 0) 
    {	MapNode::P n = new MapNode(key,obj);
    	if (c < 0) {
    	    n->m_left.take(m_root->m_left);
    	    n->m_right.take(m_root);
    	} else {
    	    n->m_right.take(m_root->m_right);
    	    n->m_left.take(m_root);
    	}
    	m_root.take(n);
    }
		else
			obj->GCunuse();
  }
}


Object *SelfishMap_i_index(Object *_this, Object *key)
{ Object *r=O_MAP->getOptionalData(key);
  if (!r)
		Map_i_insertAt(_this,key,NullObject::obj());
  return (*M_ROOTPTR)->m_data;
}

void Map_i_removeAt(Object *_this, Object *key,void *space)
{
  O_MAP->makeEditable(); // before getting pointer
	MapNode::P &m_root=*M_ROOTPTR;
  if (!m_root) { new (space) NullObject(); return; }
	O_MAP->splay(key);
	if (m_root->key()->objCompare(key) != 0)
	{ new (space) NullObject(); return; 
	}
	// Now delete the root
  m_root->m_data->duplicateIn(space);
	ChildrenPainter cp((Object *)space);
	if (!m_root->m_left) { 
      m_root.take(m_root->m_right);
	} else {
  	MapNode::P x; 
    x.take(m_root->m_right);
    m_root.take(m_root->m_left);
    O_MAP->splay(key);
    m_root->m_right.take(x);
	}
}

/*
MapNode::MapNode(const MapNode &copyFrom): 
  m_left(copyFrom.m_left), m_right(copyFrom.m_right), m_data(copyFrom.m_data->copy())
{ copyFrom.key()->duplicateIn(m_keySpace); 
}
*/
void Map_i_shiftLeft(Object *_this, Object *o,void *space)
{ MapObject *m=new (space) MapObject();
  List<MapNode *> l;
  if (!*M_ROOTPTR) return; 
  O_MAP->makeEditable();
  O_MAP->splay(o);
  if ( (*M_ROOTPTR)->key()->objCompare(o) < 0 )
	{  m->m_rootPtr->take(*M_ROOTPTR);
	  M_ROOTPTR->take((*m->m_rootPtr)->m_right);
	}
	else	
  	m->m_rootPtr->take((*M_ROOTPTR)->m_left);
}
void Map_i_shiftRight(Object *_this, Object *o,void *space)
{ MapObject *m=new (space) MapObject();
  List<MapNode *> l;
  if (!*M_ROOTPTR) return; 
  O_MAP->makeEditable();
  O_MAP->splay(o);
  if ( (*M_ROOTPTR)->key()->objCompare(o) > 0 )
	{  m->m_rootPtr->take(*M_ROOTPTR);
	  M_ROOTPTR->take((*m->m_rootPtr)->m_left);
	}
	else	
  	m->m_rootPtr->take((*M_ROOTPTR)->m_right);
}

void MapObject::splay(const Object *key) const
{ 
	MapNode::P &m_root=*m_rootPtr;
  EmptyMapNode header;
  MapNode::P y, t;
  MapNode *l=(MapNode *)&header, *r=(MapNode *)&header;
  t.take(m_root);
  for (;;)
  { int c=key->objCompare(t->key());
    if ( c< 0) {
      if (!t->m_left) break;
      if (key->objCompare(t->m_left->key()) < 0) {
          y.take(t->m_left);                            /* rotate right */
          t->m_left.take(y->m_right);
          y->m_right.take(t);
          t.take(y);
          if (!t->m_left) break;
      }
      r->m_left.take(t);                                 /* link right */
      r = r->m_left;
      t.take(r->m_left);
    } 
    else if (c > 0) {
      if (!t->m_right) break;
      if ( key->objCompare(t->m_right->key()) > 0) {
        y.take(t->m_right);                            /* rotate left */
        t->m_right.take(y->m_left);
        y->m_left.take(t);
        t.take(y);
        if (!t->m_right) break;
      }
      l->m_right.take(t);                                /* link left */
      l = l->m_right;
      t.take(l->m_right);
    } 
    else {
      break;
    }
	}
	l->m_right.take(t->m_left);                                   /* assemble */
	r->m_left.take(t->m_right);
	t->m_left.take(header.m_right);
	t->m_right.take(header.m_left);
	m_root.take(t);
}

String RegExp_i_constToString(const Object *_this) { return M_REGEXP->m_expr; }

void RegExp_i_add(Object *_this, Object *o) 
{ 
  Ptr<RE::Expr>::Share p;
  new(p) RE::Expr(M_REGEXP,o->constToString(),o->vtable != &vtable_RegExp);
  M_REGEXP=p;
}

void RegExp_i_findIndex(Object *_this, Object *b, void *space) 
{ 
	session.m_curTypePtr = &RegExpResultType;
  List<RE::Match> matches;
  String s=b->constToString(); // todo: make use of segments
  M_REGEXP->match(&matches,s,s.length());
  OList res;
	OList::P ri(&res);
	FOREACH(List<RE::Match>, matches,i)
	{ OList m;
	  { OList regs;
    	OList::P regsi(&regs);
	    FOREACH(List<String>, i->m_regs,j)
  	  { regsi->prepend(NEW_OBJ StringObject(*j));
        regsi++;
  	  }
  	  m.prepend(NEW_OBJ ListObject(regs));
	  }
	  m.prepend(NEW_OBJ IntegerObject(i->m_len));
    m.prepend(NEW_OBJ IntegerObject(i->m_pos));
    ri->prepend(NEW_OBJ ListObject(m));
    ri++;
	}
  new (space) ListObject(res);
  //m_regExpStruct
}

void Object::GCStartPaint() { session.GCPaint();  }
void Object::GCunuse() { IF_MALLOC_VERBOSE_GC(_TV(p,this); _PRINTF("Unuse: ");_TRACE;) objectGC.unuse(this);}

////////////// vtables
VTObject vtable_Char          = { TOT_String, Char_i_toInt, Char_i_hash, Char_i_length, Char_i_compare, Char_i_objCompare, Char_i_strcmp, Char_i_toTyle, Char_i_constToString, Char_i_getConstOrCopiedList, Char_i_getConstOrCopiedList, _i_getEditableList, Char_i_toFloat, _i_makeExpr, _i_containsRef, Char_i_sub, _i_div, _i_subFromMap, Char_i_index_i, _i_index, Char_i_indexCopy_i,String_i_apply,_i_applyToVoid, Char_i_duplicateIn, _i_evaluateToVoid,_i_GCPaintMyChildren, _i_toArray, Char_i_toStringList, Char_i_destroy, _i_negate_bitNot, _i_negate_bitNot, _i_selectElements, Char_i_add, Char_i_mul, Char_i_prepend, _i_binfunc, _i_binfunc, _i_binfunc, Char_i_shiftLeft, Char_i_shiftRight, _i_mod, _i_insertAt, _i_removeAt, _i_actOnColumns, Char_i_findIndex, Char_i_duplicateIn, Char_i_getIterList, 0 };
VTObject vtable_Expr          = { TOT_Expr  , _i_toInt, Expr_i_hash, _i_length, _i_compare, Expr_i_objCompare, _i_strcmp, ExprListMap_i_toTyle, Expr_i_constToString, Expr_i_getConstOrCopiedList, Expr_i_getConstOrCopiedList, _i_getEditableList, _i_toFloat, _i_makeExpr, _i_containsRef, _i_sub, _i_div, _i_subFromMap, _i_index_i, _i_index, _i_indexCopy_i,Expr_i_apply,Expr_i_applyToVoid, Expr_i_evaluateToCopy, Expr_i_evaluateToVoid, _i_GCPaintMyChildren, Expr_i_toArray, _i_toStringList, Expr_i_destroy, _i_negate_bitNot, Expr_i_bitNot, _i_selectElements, _i_binfunc, _i_binfunc, _i_binfunc, _i_binfunc, _i_binfunc, _i_binfunc, _i_shift, _i_shift, _i_mod, _i_insertAt, _i_removeAt, _i_actOnColumns, _i_findIndex, Expr_i_duplicateIn, _i_getIterList, 0 };
VTObject vtable_ClosuredExpr  = { TOT_Expr  , _i_toInt, ClosuredExpr_i_hash, _i_length, _i_compare, Expr_i_objCompare, _i_strcmp, ExprListMap_i_toTyle, ClosuredExpr_i_constToString, Expr_i_getConstOrCopiedList, Expr_i_getConstOrCopiedList, _i_getEditableList, _i_toFloat, ClosuredExpr_i_makeExpr, _i_containsRef, _i_sub, _i_div, _i_subFromMap, _i_index_i, _i_index, _i_indexCopy_i,ClosuredExpr_i_apply, ClosuredExpr_i_applyToVoid, ClosuredExpr_i_evaluateToCopy, ClosuredExpr_i_evaluateToVoid, ClosuredExpr_i_GCPaintMyChildren, ClosuredExpr_i_toArray, _i_toStringList, ClosuredExpr_i_destroy, _i_negate_bitNot, Expr_i_bitNot, _i_selectElements, _i_binfunc, _i_binfunc, _i_binfunc, _i_binfunc, _i_binfunc, _i_binfunc, _i_shift, _i_shift, _i_mod, _i_insertAt, _i_removeAt, _i_actOnColumns, _i_findIndex, ClosuredExpr_i_duplicateIn, _i_getIterList, 0 };
VTObject vtable_Float         = { TOT_Float , Float_i_toInt, Float_i_hash, _i_length, Float_i_compare, Float_i_objCompare, _i_strcmp, Float_i_toTyle, Float_i_constToString, _i_getConstOrCopiedList, _i_getConstOrCopiedList, _i_getEditableList, Float_i_toFloat, _i_makeExpr, _i_containsRef, Float_i_sub, Float_i_div, _i_subFromMap, _i_index_i, _i_index, _i_indexCopy_i,Float_i_apply, _i_applyToVoid, Float_i_duplicateIn, _i_evaluateToVoid, _i_GCPaintMyChildren, _i_toArray, _i_toStringList, Float_i_destroy, Float_i_negate, _i_negate_bitNot, _i_selectElements, Float_i_add, Float_i_mul, _i_binfunc, _i_binfunc, _i_binfunc, _i_binfunc, _i_shift, _i_shift, Float_i_mod, _i_insertAt, _i_removeAt, _i_actOnColumns, _i_findIndex, Float_i_duplicateIn, _i_getIterList, 0 };
VTObject vtable_Integer       = { TOT_Int   , Integer_i_toInt, Integer_i_hash, _i_length, Integer_i_compare, Integer_i_objCompare, _i_strcmp, Integer_i_toTyle, Integer_i_constToString, _i_getConstOrCopiedList, _i_getConstOrCopiedList, _i_getEditableList, Integer_i_toFloat, _i_makeExpr, _i_containsRef, Integer_i_sub, Integer_i_div, _i_subFromMap, _i_index_i, _i_index, _i_indexCopy_i,Integer_i_apply,_i_applyToVoid, Integer_i_duplicateIn, _i_evaluateToVoid, _i_GCPaintMyChildren, _i_toArray, _i_toStringList, Integer_i_destroy, Integer_i_negate, Integer_i_bitNot, _i_selectElements, Integer_i_add, Integer_i_mul, _i_binfunc, Integer_i_bitAnd, Integer_i_bitOr, Integer_i_bitXor, Integer_i_shiftLeft, Integer_i_shiftRight, Integer_i_mod, _i_insertAt, _i_removeAt, _i_actOnColumns, _i_findIndex, Integer_i_duplicateIn, _i_getIterList, 0 };
VTObject vtable_List          = { TOT_List  , List_i_toInt, List_i_hash, List_i_length, List_i_compare, List_i_objCompare, _i_strcmp, ExprListMap_i_toTyle, List_i_constToString, List_i_getConstList, List_i_getCopiedList, List_i_getEditableList, _i_toFloat, List_i_makeExpr, List_i_containsRef, List_i_sub, List_i_div, _i_subFromMap, List_i_index_i, _i_index, List_i_indexCopy_i,List_i_apply,_i_applyToVoid, List_i_duplicateIn, _i_evaluateToVoid, List_i_GCPaintMyChildren, List_i_toArray, List_i_toStringList, List_i_destroy, List_i_negate, List_i_bitNot, _i_selectElements, List_i_add, List_i_mul, List_i_prepend, List_i_bitAnd, List_i_bitOr, List_i_bitXor, List_i_shiftLeft, List_i_shiftRight, List_i_mod, List_i_insertAt, List_i_removeAt, _i_actOnColumns, List_i_findIndex, List_i_duplicateIn, _i_getIterList, 0 };
VTObject vtable_Map           = { TOT_Map   , Map_i_toInt, Map_i_hash, Map_i_length, Map_i_compare, Map_i_objCompare, _i_strcmp, ExprListMap_i_toTyle, _i_constToString, Map_i_getConstOrCopiedList, Map_i_getConstOrCopiedList, Map_i_getEditableList, _i_toFloat, Map_i_makeExpr, Map_i_containsRef, Map_i_sub, _i_div, Map_i_subFromMap, Map_i_index_i, Map_i_index, Map_i_indexCopy_i,Map_i_apply,_i_applyToVoid, Map_i_duplicateIn, _i_evaluateToVoid, Map_i_GCPaintMyChildren, Map_i_toArray, _i_toStringList, Map_i_destroy, _i_negate_bitNot, _i_negate_bitNot, Map_i_selectElements, Map_i_add, _i_binfunc, _i_binfunc, _i_binfunc, _i_binfunc, _i_binfunc, Map_i_shiftLeft, Map_i_shiftRight, _i_mod, Map_i_insertAt, Map_i_removeAt, Map_i_actOnColumns, Map_i_findIndex, Map_i_duplicateIn, Map_i_getIterList, 0 };
VTObject vtable_Null          = { TOT_Null  , _i_toInt, _i_hash, _i_length, _i_compare, _i_objCompare, _i_strcmp, Null_i_toTyle, _i_constToString, _i_getConstOrCopiedList, _i_getConstOrCopiedList, _i_getEditableList, _i_toFloat, _i_makeExpr, _i_containsRef, _i_sub, _i_div, _i_subFromMap, _i_index_i, _i_index, _i_indexCopy_i,Null_i_apply,Null_i_applyToVoid, Null_i_duplicateIn, _i_evaluateToVoid, _i_GCPaintMyChildren, _i_toArray, _i_toStringList, Null_i_destroy, _i_negate_bitNot, _i_negate_bitNot, _i_selectElements, _i_binfunc, _i_binfunc, _i_binfunc, _i_binfunc, _i_binfunc, _i_binfunc, _i_shift, _i_shift, _i_mod, _i_insertAt, _i_removeAt, _i_actOnColumns, _i_findIndex, Null_i_duplicateIn, _i_getIterList, 0 };
VTObject vtable_Ref           = { TOT_Ref   , Ref_i_toInt, Ref_i_hash, Ref_i_length, Ref_i_compare, Ref_i_objCompare, _i_strcmp, Ref_i_toTyle, Ref_i_constToString, Ref_i_getConstList, Ref_i_getCopiedList, Ref_i_getEditableList, Ref_i_toFloat, Ref_i_makeExpr, Ref_i_containsRef, Ref_i_sub, Ref_i_div, Ref_i_subFromMap, Ref_i_index_i, Ref_i_index, Ref_i_indexCopy_i,Ref_i_apply,Ref_i_applyToVoid, Ref_i_evaluateToCopy, Ref_i_evaluateToVoid, Ref_i_GCPaintMyChildren, Ref_i_toArray, _i_toStringList, Ref_i_destroy, Ref_i_negate, Ref_i_bitNot, Ref_i_selectElements, Ref_i_add, Ref_i_mul, Ref_i_prepend, Ref_i_bitAnd, Ref_i_bitOr, Ref_i_bitXor, Ref_i_shiftLeft, Ref_i_shiftRight, Ref_i_mod, Ref_i_insertAt, Ref_i_removeAt, Ref_i_actOnColumns, Ref_i_findIndex, Ref_i_duplicateIn, Ref_i_getIterList, 0 };
VTObject vtable_RegExp        = { TOT_RegExp, _i_toInt, RegExp_i_hash, _i_length, _i_compare, RegExp_i_objCompare, _i_strcmp, RegExp_i_toTyle, RegExp_i_constToString, _i_getConstOrCopiedList, _i_getConstOrCopiedList, _i_getEditableList, _i_toFloat, _i_makeExpr, _i_containsRef, _i_sub, _i_div, _i_subFromMap, _i_index_i, _i_index, _i_indexCopy_i,RegExp_i_apply,_i_applyToVoid,RegExp_i_duplicateIn, _i_evaluateToVoid, _i_GCPaintMyChildren, _i_toArray, _i_toStringList, RegExp_i_destroy, _i_negate_bitNot, _i_negate_bitNot, _i_selectElements, RegExp_i_add, _i_binfunc, _i_binfunc, _i_binfunc, _i_binfunc, _i_binfunc, _i_shift, _i_shift, _i_mod, _i_insertAt, _i_removeAt, _i_actOnColumns, RegExp_i_findIndex, RegExp_i_duplicateIn, _i_getIterList, 0 };
VTObject vtable_SelfishList   = { TOT_List  , List_i_toInt, List_i_hash, List_i_length, List_i_compare, List_i_objCompare, _i_strcmp, ExprListMap_i_toTyle, List_i_constToString, List_i_getConstList, List_i_getCopiedList, List_i_getEditableList, _i_toFloat, List_i_makeExpr, List_i_containsRef, List_i_sub, List_i_div, _i_subFromMap, SelfishList_i_index_i, _i_index, List_i_indexCopy_i,List_i_apply,_i_applyToVoid,SelfishList_i_duplicateIn, _i_evaluateToVoid, List_i_GCPaintMyChildren, List_i_toArray, List_i_toStringList, SelfishList_i_destroy, List_i_negate, List_i_bitNot, _i_selectElements, List_i_add, List_i_mul, List_i_prepend, List_i_bitAnd, List_i_bitOr, List_i_bitXor, List_i_shiftLeft, List_i_shiftRight, List_i_mod, List_i_insertAt, List_i_removeAt, _i_actOnColumns, List_i_findIndex, SelfishList_i_duplicateIn, _i_getIterList, SelfishList_i_persist };
VTObject vtable_SelfishMap    = { TOT_Map   , Map_i_toInt, Map_i_hash, Map_i_length, Map_i_compare, Map_i_objCompare, _i_strcmp, ExprListMap_i_toTyle, _i_constToString, Map_i_getConstOrCopiedList, Map_i_getConstOrCopiedList, Map_i_getEditableList, _i_toFloat, Map_i_makeExpr, Map_i_containsRef, Map_i_sub, _i_div, Map_i_subFromMap, Map_i_index_i, SelfishMap_i_index, Map_i_indexCopy_i,Map_i_apply,_i_applyToVoid,SelfishMap_i_duplicateIn, _i_evaluateToVoid, Map_i_GCPaintMyChildren, Map_i_toArray, _i_toStringList, SelfishMap_i_destroy, _i_negate_bitNot, _i_negate_bitNot, Map_i_selectElements, Map_i_add, _i_binfunc, _i_binfunc, _i_binfunc, _i_binfunc, _i_binfunc, Map_i_shiftLeft, Map_i_shiftRight, _i_mod, Map_i_insertAt, Map_i_removeAt, Map_i_actOnColumns, Map_i_findIndex, SelfishMap_i_duplicateIn, Map_i_getIterList, SelfishMap_i_persist };
VTObject vtable_String        = { TOT_String, String_i_toInt, String_i_hash, String_i_length, String_i_compare, String_i_objCompare, _i_strcmp, String_i_toTyle, String_i_constToString, String_i_getConstOrCopiedList, String_i_getConstOrCopiedList, _i_getEditableList, String_i_toFloat, _i_makeExpr, _i_containsRef, String_i_sub, String_i_div, _i_subFromMap, String_i_index_i, _i_index, String_i_indexCopy_i,String_i_apply,_i_applyToVoid,String_i_duplicateIn,_i_evaluateToVoid,_i_GCPaintMyChildren, _i_toArray, _i_toStringList, String_i_destroy, String_i_negate, _i_negate_bitNot, _i_selectElements, String_i_add, String_i_mul, String_i_prepend, _i_binfunc, _i_binfunc, _i_binfunc, String_i_shiftLeft, String_i_shiftRight, _i_mod, _i_insertAt, _i_removeAt, _i_actOnColumns, String_i_findIndex, String_i_duplicateIn, String_i_getIterList, 0 };
VTObject vtable_StringSegment = { TOT_String, StringSegment_i_toInt, StringSegment_i_hash, StringSegment_i_length, StringSegment_i_compare, StringSegment_i_objCompare, StringSegment_i_strcmp, StringSegment_i_toTyle, StringSegment_i_constToString, StringSegment_i_getConstOrCopiedList, StringSegment_i_getConstOrCopiedList, _i_getEditableList, StringSegment_i_toFloat, _i_makeExpr, _i_containsRef, StringSegment_i_sub, _i_div, _i_subFromMap, StringSegment_i_index_i, _i_index, StringSegment_i_indexCopy_i,String_i_apply,_i_applyToVoid,StringSegment_i_duplicateIn, _i_evaluateToVoid, _i_GCPaintMyChildren, _i_toArray, StringSegment_i_toStringList, StringSegment_i_destroy, _i_negate_bitNot, _i_negate_bitNot, _i_selectElements, StringSegment_i_add, StringSegment_i_mul, StringSegment_i_prepend, _i_binfunc, _i_binfunc, _i_binfunc, StringSegment_i_shiftLeft, StringSegment_i_shiftRight, _i_mod, _i_insertAt, _i_removeAt, _i_actOnColumns, StringSegment_i_findIndex, StringSegment_i_duplicateIn, StringSegment_i_getIterList, 0 };
VTObject vtable_SelfishString = { TOT_String, String_i_toInt, String_i_hash, String_i_length, String_i_compare, String_i_objCompare, _i_strcmp, String_i_toTyle, String_i_constToString, String_i_getConstOrCopiedList, String_i_getConstOrCopiedList, _i_getEditableList, String_i_toFloat, _i_makeExpr, _i_containsRef, String_i_sub, String_i_div, _i_subFromMap, SelfishString_i_index_i, _i_index, String_i_indexCopy_i,String_i_apply,_i_applyToVoid,SelfishString_i_duplicateIn, _i_evaluateToVoid, _i_GCPaintMyChildren, _i_toArray, _i_toStringList, SelfishString_i_destroy, String_i_negate, _i_negate_bitNot, _i_selectElements, String_i_add, String_i_mul, String_i_prepend, _i_binfunc, _i_binfunc, _i_binfunc, SelfishString_i_shiftLeft, SelfishString_i_shiftRight, _i_mod, _i_insertAt, _i_removeAt, _i_actOnColumns, String_i_findIndex, SelfishString_i_duplicateIn, String_i_getIterList, SelfishString_i_persist };

////////////////////////////////////////
} //namespace

ObjectAllocator objectGC;

#ifdef MEMDEBUG_MALLOC
typedef struct{ int a; int b; Ptr<Obj::ExprObject>::Share::Dynamic::TypePtr c; int d; int e; } allocatorElem;
void *ireserveBytes(int num, char *name)
{ mcount++;//mcc++;
	//if (!(mcc&1023)) printf(":%d",mcount);
	allocatorElem *p=(allocatorElem *)mstl_alloc(sizeof(allocatorElem));
	//(allocatorElem *)new char[sizeof(allocatorElem)];//allocator.alloc();
	p->a=123456;
	p->b=567890;
	p->d=654321;
	p->e=98765;
	return &(p->c);
	//return mstl_alloc(sizeof(Ptr<ExprObject>::Share::Dynamic::TypePtr));
}

void ifreeBytes(void *v, char *name)
{ mcount--;//mcc++;
	//if (!(mcc&1023)) printf(":%d",mcount);
	allocatorElem *p=(allocatorElem *)((char *)v-sizeof(int)*2);
	if (p->a!=123456) { printf("!!a!!!%p %i!!!!\n",v,p->a); DIV_BY_ZERO(p) }
	if (p->b!=567890) { printf("!!b!!!%p %i!!!!\n",v,p->b); DIV_BY_ZERO(p) }
	if (p->d!=654321) { printf("!!d!!!%p %i!!!!\n",v,p->d); DIV_BY_ZERO(p) }
	if (p->e!=98765) { printf("!!e!!!%p %i!!!!\n",v,p->e); DIV_BY_ZERO(p) }
	p->a=p->b=p->d=p->e=0;
//	p->a=0;
//	p->c=0;
	mstl_free(p);
}
#else
BasicAllocator<8,256,2048> allocator;
#endif

/*
 void *ireserveBytes1(int num );
 void *ireserveBytes2(int num );
 void ifreeBytes1(void *v );
 void ifreeBytes2(void *v );
extern int mcount,mcc;
template<> inline void *reserveBytes<X::TypePtr>(int num )\

template<> inline void *reserveBytes<OList::TypePtr>(int num ) { return ireserveBytes1(num); }
template<> inline void *reserveBytes<OPtr::TypePtr>(int num ) { return ireserveBytes2(num); }
template<> inline void freeBytes<OList::TypePtr>(void *v ) { ifreeBytes1(v); }
template<> inline void freeBytes<OPtr::TypePtr>(void *v ) { ifreeBytes2(v); }
 void *ireserveBytes1(int num ) { void *p= allocator.alloc(); printf("OList:%p\n",p); return p;}
 void *ireserveBytes2(int num ) { void *p= allocator.alloc(); printf("OPtr:%p\n",p); return p;}
 void ifreeBytes1(void *v ) { printf("~OList:%p\n",v);allocator.free(v); }
 void ifreeBytes2(void *v ) { printf("~OPtr:%p\n",v);allocator.free(v); }
*/
